package cn.fscode.code.generator.manager;

import cn.fscode.code.generator.model.WordDataUnderTitle;
import cn.fscode.code.generator.model.WordTable;
import cn.fscode.code.generator.model.WordTableCell;
import cn.fscode.code.generator.model.WordTableRow;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author shenguangyang
 */
@Service
public class DocxManager extends WordTableManager {

    @PostConstruct
    public void init() {
        wordTableManagerMap.put(WordFileType.DOCX, this);
    }

    public static void main(String[] args) throws IOException {
        DocxManager docxManager = new DocxManager();
        List<WordDataUnderTitle> wordDataList = docxManager.getWordDataList("D:\\test.docx");
        System.out.println(wordDataList);
    }

    @Override
    public List<WordDataUnderTitle> getWordDataList(String path) throws IOException {
        File file = new File(path);
        try (FileInputStream fis = new FileInputStream(file)) {
            XWPFDocument xdoc = new XWPFDocument(fis);
            List<IBodyElement> bodyElements = xdoc.getBodyElements();
            Map<String, WordDataUnderTitle> data = new LinkedHashMap<>();
            String currentParaText = "";
            String titleLvl = "0";
            for (IBodyElement bodyElement : bodyElements) {
                if (bodyElement.getElementType() == BodyElementType.TABLE) {
                    XWPFTable xwpfTable = (XWPFTable) bodyElement;
                    WordDataUnderTitle readList = data.computeIfAbsent(currentParaText, v -> new WordDataUnderTitle());
                    readList.setTableNum(readList.getTableNum() + 1);

                    WordTable wordTable = new WordTable();
                    List<WordTableRow> wordTableRowList = new ArrayList<>();
                    for (XWPFTableRow row : xwpfTable.getRows()) {
                        WordTableRow wordTableRow = new WordTableRow();
                        List<WordTableCell> wordTableCellList = new ArrayList<>();
                        for (XWPFTableCell tableCell : row.getTableCells()) {
                            WordTableCell wordTableCell = new WordTableCell();
                            wordTableCell.setText(tableCell.getText());
                            wordTableCellList.add(wordTableCell);
                        }
                        wordTableRow.setCells(wordTableCellList);
                        wordTableRowList.add(wordTableRow);
                    }
                    wordTable.setRows(wordTableRowList);
                    readList.getWordTableList().add(wordTable);
                } else if (bodyElement.getElementType() == BodyElementType.PARAGRAPH) {
                    XWPFParagraph xwpfParagraph = (XWPFParagraph) bodyElement;
                    // 段落级别
                    titleLvl = getTitleLvl(xdoc, xwpfParagraph);
                    int level = StringUtils.isEmpty(titleLvl) ? 0 : Integer.parseInt(titleLvl);
                    if (level == 0) {
                        continue;
                    }
                    currentParaText = xwpfParagraph.getParagraphText();
                    if (StringUtils.isEmpty(currentParaText)) {
                        continue;
                    }
                    WordDataUnderTitle wordDataUnderTitle = data.computeIfAbsent(currentParaText, v -> new WordDataUnderTitle());
                    wordDataUnderTitle.setLevel(Integer.parseInt(titleLvl));
                    wordDataUnderTitle.setTitle(currentParaText);
                }
            }
            return data.entrySet().stream().filter(x -> StringUtils.isNotEmpty(x.getKey()))
                    .map(Map.Entry::getValue)
                    .collect(Collectors.toList());
        }
    }

//    public List<Object> readTableInParagraph(XWPFParagraph xwpfParagraph) {
//        List<XWPFRun> runs = xwpfParagraph.getRuns();
//
//
//    }


    /**
     * Word中的大纲级别，可以通过getPPr().getOutlineLvl()直接提取，但需要注意，Word中段落级别，通过如下三种方式定义：
     * 1、直接对段落进行定义；
     * 2、对段落的样式进行定义；
     * 3、对段落样式的基础样式进行定义。
     * 因此，在通过“getPPr().getOutlineLvl()”提取时，需要依次在如上三处读取。
     */
    public static String getTitleLvl(XWPFDocument doc, XWPFParagraph para) {
        String titleLvl = "";
        // 判断该段落是否设置了大纲级别
        CTPPr pPr = para.getCTP().getPPr();
        if (pPr != null && pPr.getOutlineLvl() != null) {
//             System.out.println("getCTP()");
//             System.out.println(para.getParagraphText());
//             System.out.println(para.getCTP().getPPr().getOutlineLvl().getVal());

            return String.valueOf(para.getCTP().getPPr().getOutlineLvl().getVal());
        }

        //判断该段落的样式是否设置了大纲级别
        if (doc.getStyles().getStyle(para.getStyle()) != null &&
                doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl() != null) {

            // System.out.println("getStyle");
//              System.out.println(para.getParagraphText());
//              System.out.println(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());

            return String.valueOf(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
        }

        //判断该段落的样式的基础样式是否设置了大纲级别
        XWPFStyle style = doc.getStyles().getStyle(para.getStyle());
        if (style != null && doc.getStyles().getStyle(style.getCTStyle().getBasedOn().getVal())
                .getCTStyle().getPPr().getOutlineLvl() != null) {
//             System.out.println("getBasedOn");
//             System.out.println(para.getParagraphText());
             String styleName = doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal();
//             System.out.println(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());

            return String.valueOf(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
        }

        if (para.getStyleID() != null) {
            return para.getStyleID();
        }
        return titleLvl;
    }
}
